package com.xteam.xnetworkdisk.utils;

import com.xteam.xnetworkdisk.constant.Constant;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;


public class VideoUtil {

    // 请确保这些参数在调用方法之前已正确初始化
    private static final int audioChannels = 2; // 设置为 0 如果不需要音频
    private static final int audioBitrate = 64000; // 设置音频比特率
    private static final int sampleRate = 44100; // 设置音频采样率

    /**
     * 获取视频封面
     * @param file 视频文件
     * @param outputStream 目标输出流
     * @throws IOException
     */
    public static void getVideoImage(MultipartFile file,OutputStream outputStream) throws IOException {
        FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(file.getInputStream());
        fFmpegFrameGrabber.start();
        int i = 0;
        int length = fFmpegFrameGrabber.getLengthInFrames();
        Frame frame = null;
        while(i<length){
            frame = fFmpegFrameGrabber.grabImage();
            // 去除前5帧
            if((i>5)&&(frame.image!=null)){
                 break;
            }
            i++;
        }
        // 写到目标输出流
        ImageIO.write(FrameToImage(frame), Constant.VIDEO_INDEX_IMAGE_TPYE,outputStream);
        fFmpegFrameGrabber.stop();
    }

    public static void getVideoImage(InputStream file,OutputStream outputStream) throws IOException {
        FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(file);
        fFmpegFrameGrabber.start();
        int i = 0;
        int length = fFmpegFrameGrabber.getLengthInFrames();
        Frame frame = null;
        while(i<length){
            frame = fFmpegFrameGrabber.grabImage();
            // 去除前5帧
            if((i>5)&&(frame.image!=null)){
                break;
            }
            i++;
        }
        // 写到目标输出流
        ImageIO.write(FrameToImage(frame), Constant.VIDEO_INDEX_IMAGE_TPYE,outputStream);
        fFmpegFrameGrabber.stop();
    }


    /**
     * 判断视频格式
     * @param contentType
     * @return
     */
    public static boolean isVideoFile(String contentType) {
        return contentType != null && Constant.VIDEO_CONTENT_TYPES.contains(contentType.toLowerCase());
    }


    // 帧转换为图片
    private static BufferedImage FrameToImage(Frame frame){
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage image = converter.getBufferedImage(frame);
        return image;
    }

    public static void generateM3U8(InputStream inputStream,String destDirectory,String fileName) {
        FFmpegFrameRecorder recorder = null;
        FFmpegFrameGrabber grabber = null;
        long frameCountToRecord;
        long framesRecorded = 0;
        try {
            // 创建 FFmpegFrameGrabber 对象
            grabber = new FFmpegFrameGrabber(inputStream);
            grabber.start();

            // 获取视频帧率
            double frameRate = grabber.getFrameRate();
            // 计算一分钟需要的帧数
            frameCountToRecord = (long) (frameRate * 60 * 5);

            String[] strings = Tools.splitFileName(fileName);
            String fName = strings[0];

            // 设置 FFmpegFrameRecorder 进行 HLS 转码
            File m3u8File = new File(destDirectory, fName+".m3u8");
            recorder = new FFmpegFrameRecorder(m3u8File, grabber.getImageWidth(), grabber.getImageHeight(), audioChannels);
            recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.setAudioBitrate(audioBitrate);
            recorder.setAudioChannels(audioChannels);
            recorder.setSampleRate(grabber.getSampleRate());
            recorder.setFrameRate(grabber.getFrameRate()); // 确保帧速率设置正确
            recorder.setVideoBitrate(400000); // 确保视频比特率设置合理
            recorder.setFormat("hls");
            recorder.setOption("hls_time", "10"); // 每个 TS 文件的时长，单位为秒
            recorder.setOption("hls_list_size", "0"); // 不限制播放列表中的 TS 文件数量
            recorder.setOption("hls_segment_filename", new File(destDirectory, fName + "_%03d.ts").getAbsolutePath()); // TS 文件的前缀
            recorder.start();



            // 读取视频流并写入到 HLS 文件
            while (framesRecorded < frameCountToRecord) {
                org.bytedeco.javacv.Frame frame = grabber.grab();
                if (frame == null) {
                    break;
                }
                recorder.record(frame);
                framesRecorded++;
            }


        } catch (FFmpegFrameGrabber.Exception e) {
            throw new RuntimeException(e);
        } catch (FFmpegFrameRecorder.Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 确保正确停止录制和抓取
            try {
                if (recorder != null) {
                    recorder.stop();
                }
                if (grabber != null) {
                    grabber.stop();
                }
            } catch (FFmpegFrameRecorder.Exception | FFmpegFrameGrabber.Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void generateM3U8Local(String inputFilePath, String destDirectory, String fileName) {
        ProcessBuilder processBuilder = new ProcessBuilder();
        // 指定批处理文件路径
        String batFilePath = Constant.M3U8_SHELL_PATH; // 修改为实际的批处理文件路径
        String shellProgram = Constant.SHELL_PROGRAM; // 修改为实际的 shell 程序路径

        // 构建命令行参数
        if(Constant.DEVICE_TYPE == Constant.DEVICE_WINDOWS) {
            processBuilder.command(shellProgram, "/c", batFilePath, inputFilePath, destDirectory, fileName);
        }else {
            processBuilder.command(shellProgram, batFilePath, inputFilePath, destDirectory, fileName);
        }

        try {
            // 启动批处理进程
            System.out.println("启动进程");
            Process process = processBuilder.start();

            // 读取标准输出和错误输出
            new Thread(() -> {
                try (BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = outputReader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                    String line;
                    while ((line = errorReader.readLine()) != null) {
                        System.err.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            // 等待批处理进程执行完成
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("HLS conversion completed successfully.");
            } else {
                System.err.println("HLS conversion failed with exit code " + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void generateM3U8External(String fullPathTS, String destDirectory, String fileNameR) {
        System.out.println("生成外部访问m3u8");
        String outputFileName = fileNameR + "_e.m3u8";
        String outputFilePath = destDirectory + outputFileName;

        try {
            // 读取初始的 m3u8 文件
            List<String> lines = Files.readAllLines(Paths.get(fullPathTS));

            // 新增一个前缀到每个 .ts 文件前面
            List<String> modifiedLines = lines.stream()
                    .map(line -> {
                        if (line.endsWith(".ts")) {
                            // 在这里添加你想要的前缀
                            String prefix = Constant.FILE_LOCAL_PATH +"/" + Constant.USER_FILE_BUKET + "/" + Constant.PREVIEW_SEGMENT +"/"; // 可以根据需要动态生成
                            return prefix + line;
                        }
                        return line;
                    })
                    .collect(Collectors.toList());

            // 将修改后的内容写入新的 m3u8 文件
            Files.write(Paths.get(outputFilePath), modifiedLines);

            System.out.println("新的 m3u8 文件已生成: " + outputFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}